package com.zzyl.security;

import com.alibaba.fastjson.JSON;
import com.zzyl.constant.SecurityConstant;
import com.zzyl.constant.UserCacheConstant;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.UserVo;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Component
@Slf4j
public class JwtAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication,
                                       RequestAuthorizationContext requestContext) {
        // 1.获取jwtToken
        String userUUID = requestContext.getRequest().getHeader(SecurityConstant.USER_TOKEN);
        if (EmptyUtil.isNullOrEmpty(userUUID)){
            return new AuthorizationDecision(false);
        }

        String jwtTokenKey = UserCacheConstant.JWT_TOKEN+userUUID;
        String jwtToken = redisTemplate.opsForValue().get(jwtTokenKey);
        if (EmptyUtil.isNullOrEmpty(jwtToken)){
            return new AuthorizationDecision(false);
        }

        // 2.解析jwtToken
        String userJSON = JwtUtil.parseJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(),
                jwtToken).get("currentUser").toString();
        UserVo userVo = JSON.parseObject(userJSON, UserVo.class);
        if (EmptyUtil.isNullOrEmpty(userVo.getUsername())) {
            return new AuthorizationDecision(false);
        }

        // 3.判断uuid是否相同
        String userTokenKey = UserCacheConstant.USER_TOKEN + userVo.getUsername();
        String uuid = redisTemplate.opsForValue().get(userTokenKey);
        if (Objects.equals(uuid, userUUID)) {
            return new AuthorizationDecision(false);
        }

        // 4.重置过期时间
        Long expire = redisTemplate.opsForValue().getOperations()
                .getExpire(jwtTokenKey);
        if (expire.longValue() <= 600) {
            //jwt生成的token也会过期，故需要再次生成
            Map<String, Object> claims = new HashMap<>();
            claims.put("currentUser", JSON.toJSONString(userVo));
            String token = JwtUtil.createJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(),
                    jwtTokenManagerProperties.getTtl(), claims);
            long ttl = jwtTokenManagerProperties.getTtl() / 1000;

            redisTemplate.opsForValue().set(jwtTokenKey, token, ttl, TimeUnit.SECONDS);
            redisTemplate.expire(userTokenKey, ttl, TimeUnit.SECONDS);
        }
        return new AuthorizationDecision(true);
    }
}
